package com.example.demo.websockerServer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @Name : com.example.demo.websockerServer.WebsocketTest
 * @Description : ws://localhost:8081/websocketTest/user001
 * Created by cyd on 2021-02-07 16:04:50
 */

@Component
@ServerEndpoint(value = "/websocketTest/{userId}")
public class WebsocketTestService {

    private final Logger logger = LoggerFactory.getLogger(WebsocketTestService.class);

    private String userId;

    /**
     * 与某个客户端的连接会话
     * 需要通过它来给当前客户端发送数据
     **/
    private Session session;

    /**
     * 用来存放每个客户端对应的MyWebSocket对象
     * 可以用它来获取所有的session，发送异步消息
     **/
    private static final CopyOnWriteArraySet<WebsocketTestService> webSocketSet = new CopyOnWriteArraySet<>();

    /**
     * 可以用它来获取所有的session，发送异步消息
     **/
    private static final Map<String, Session> sessionsMap = new HashMap<String, Session>();

    //连接时执行
    @OnOpen
    public void onOpen(@PathParam("userId") String userId, Session session) throws IOException {
        this.userId = userId;
        this.session = session;
        sessionsMap.put(userId, session);
        webSocketSet.add(this);
        logger.info("新连接：{}", userId);
        // 广播群发消息
        broadcastNotify(this.userId, "进入了聊天室");

        List<String> params = this.session.getRequestParameterMap().get("userId");
        logger.info("params：{}", params);
    }

    //关闭时执行
    @OnClose
    public void onClose() {
        logger.info("连接：{} 关闭", this.userId);
        // 广播群发消息
        broadcastNotify(this.userId, "离开了聊天室");
        webSocketSet.remove(this);
        sessionsMap.remove(this.userId);
    }

    //收到消息时执行
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {

        logger.info("收到{}的消息{}", this.userId, message);
        // 给自己发，相当于服务器回复
        this.session.getBasicRemote().sendText("您发送消息 " + ":" + message);
        // 广播群发消息
        broadcast(this.userId, message);
    }


    //连接错误时执行
    @OnError
    public void onError(Session session, Throwable error) {
        logger.info("用户id为：{}的连接发送错误", this.userId);
        error.printStackTrace();
    }

    private void broadcast(String userId, String message) {
        Session session = sessionsMap.get(userId);

        for (WebsocketTestService item : webSocketSet) {
            // 不给自己发
            if (session == item.session) {
                continue;
            }

            /**
             * 同步异步说明参考：http://blog.csdn.net/who_is_xiaoming/article/details/53287691
             *
             * this.session.getBasicRemote().sendText(message);
             **/
            item.session.getAsyncRemote().sendText(userId + "-发送消息：" + message);
        }

    }

    private void broadcastNotify(String userId, String message) {
        Session session = sessionsMap.get(userId);

        for (WebsocketTestService item : webSocketSet) {
            // 不给自己发
            if (session == item.session) {
                continue;
            }

            /**
             * 同步异步说明参考：http://blog.csdn.net/who_is_xiaoming/article/details/53287691
             *
             * this.session.getBasicRemote().sendText(message);
             **/
            item.session.getAsyncRemote().sendText("通知-" + userId + "-" + message);
        }

    }
}
